package handler

import (
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"myai/core/types"
	"myai/store/model"
	"myai/store/model/req"
	"myai/store/vo"
	"myai/utils"
	"myai/utils/resp"
)

// List godoc
// @Summary      获取会话列表
// @Description  获取会话列表
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Success      200  {object}  types.BizVo{data=[]vo.ChatItem}
// @Router       /api/chat/list [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) List(c *gin.Context) {
	// 判断用户是否登录，如果没有登录直接返回
	if !h.IsLogin(c) {
		resp.SUCCESS(c)
		return
	}

	userId := h.GetLoginUserId(c)
	var items = make([]vo.ChatItem, 0)
	var chats []model.ChatItem
	// 查询用户会话数据
	h.DB.Where("user_id", userId).Order("id desc").Find(&chats)
	if len(chats) == 0 {
		resp.SUCCESS(c, items)
		return
	}
	// 应用角色Id集合
	var roleIds = make([]uint, 0)
	// 模型集合
	var modelValues = make([]string, 0)
	for _, chat := range chats {
		roleIds = append(roleIds, chat.RoleId)
		modelValues = append(modelValues, chat.Model)
	}

	var roles []model.ChatRole
	var models []model.ChatModel
	roleMap := make(map[uint]model.ChatRole)
	modelMap := make(map[string]model.ChatModel)
	// 查询应用角色信息
	h.DB.Where("id IN ?", roleIds).Find(&roles)
	// 查询模型信息
	h.DB.Where("value IN ?", modelValues).Find(&models)

	for _, role := range roles {
		roleMap[role.Id] = role
	}

	for _, m := range models {
		modelMap[m.Value] = m
	}

	for _, chat := range chats {
		var item vo.ChatItem
		err := utils.CopyObject(chat, &item)
		if err == nil {
			item.Id = chat.Id
			// 设置会话图标，从会话关联的应用角色信息中获取
			item.Icon = roleMap[chat.RoleId].Icon
			// 获取会话模型Id
			item.ModelId = modelMap[chat.Model].Id
			items = append(items, item)
		}
	}
	resp.SUCCESS(c, items)
}

// Update godoc
// @Summary      更新用户会话标题
// @Description  更新用户会话标题
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Param        req   body    req.ChatItemUpdateByTitle  true  "会话标题信息"
// @Success      200  {object}  types.BizVo{}
// @Router       /api/chat/update [post]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) Update(c *gin.Context) {
	var data req.ChatItemUpdateByTitle
	if err := c.ShouldBindJSON(&data); err != nil {
		resp.ERROR(c, types.InvalidArgs)
		return
	}
	res := h.DB.Model(&model.ChatItem{}).Where("chat_id = ?", data.ChatId).UpdateColumn("title", data.Title)
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+res.Error.Error())
		return
	}
	resp.SUCCESS(c, types.OkMsg)
}

// Clear godoc
// @Summary      清空所有会话记录包括会话中的聊天记录
// @Description  清空所有会话记录包括会话中的聊天记录
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Success      200  {object}  types.BizVo{}
// @Router       /api/chat/clear [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) Clear(c *gin.Context) {
	// 获取当前登录的用户信息
	user, err := h.GetLoginUser(c)
	if err != nil {
		resp.NotAuth(c)
		return
	}

	// 查询用户的会话记录
	var chats []model.ChatItem
	res := h.DB.Where("user_id = ?", user.Id).Find(&chats)
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+res.Error.Error())
		return
	}

	var chatIds = make([]string, 0)
	for _, chat := range chats {
		chatIds = append(chatIds, chat.ChatId)
		// 清空会话上下文
		h.ClearChatCtx(chat.ChatId)
	}
	// Transaction 方法会自动根据闭包函数的执行结果决定提交或回滚事务。如果闭包返回 nil（无错误），事务会被提交；若闭包返回错误，事务会自动回滚
	err = h.DB.Transaction(func(tx *gorm.DB) error {
		// 删除会话
		res := h.DB.Where("user_id = ?", user.Id).Delete(&model.ChatItem{})
		if res.Error != nil {
			return res.Error
		}
		// 删除会话记录中的消息
		res = h.DB.Where("user_id = ? and chat_id IN ?", user.Id, chatIds).Delete(&model.ChatMessage{})
		if res.Error != nil {
			return res.Error
		}
		return nil
	})

	if err != nil {
		log.Errorf("操作数据库出现错误：%+v", err)
		resp.ERROR(c, "操作数据库出现错误："+err.Error())
		return
	}
	resp.SUCCESS(c, types.OkMsg)
}

// History godoc
// @Summary      获取会话聊天历史记录
// @Description  获取会话聊天历史记录
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Param        chat_id   query     string  true  "会话Id"
// @Success      200  {object}  types.BizVo{data=[]vo.HistoryMessage}
// @Router       /api/chat/history [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) History(c *gin.Context) {
	chatId := h.GetTrim(c, "chat_id")
	// 判断参数是否为空
	if utils.IsEmptyValue(chatId) {
		resp.ERROR(c, types.InvalidArgs)
		return
	}

	var items []model.ChatMessage
	var messages = make([]vo.HistoryMessage, 0)
	// 查询会话聊天历史记录
	res := h.DB.Where("chat_id = ?", chatId).Find(&items)
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+res.Error.Error())
		return
	} else {
		for _, item := range items {
			var v vo.HistoryMessage
			err := utils.CopyObject(item, &v)
			if err != nil {
				log.Errorf("拷贝数据出现错误：" + err.Error())
				continue
			}
			v.Id = item.Id
			v.CreatedAt = item.CreatedAt.Unix()
			v.UpdatedAt = item.UpdatedAt.Unix()
			messages = append(messages, v)
		}
	}
	resp.SUCCESS(c, messages)
}

// HistoryLastTwoMsg godoc
// @Summary      获取会话聊天历史记录的最后两条消息
// @Description  获取会话聊天历史记录的最后两条消息
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Param        chat_id   query     string  true  "会话Id"
// @Success      200  {object}  types.BizVo{data=[]vo.HistoryMessage}
// @Router       /api/chat/historyLastTwoMsg [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) HistoryLastTwoMsg(c *gin.Context) {
	chatId := h.GetTrim(c, "chat_id")
	// 判断参数是否为空
	if utils.IsEmptyValue(chatId) {
		resp.ERROR(c, types.InvalidArgs)
		return
	}

	var items []model.ChatMessage
	var messages = make([]vo.HistoryMessage, 0)
	// 查询会话聊天历史记录
	res := h.DB.Where("chat_id = ?", chatId).Order("id desc").Limit(2).Find(&items)
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+res.Error.Error())
		return
	} else {
		for _, item := range items {
			var v vo.HistoryMessage
			err := utils.CopyObject(item, &v)
			if err != nil {
				log.Errorf("拷贝数据出现错误：" + err.Error())
				continue
			}
			v.Id = item.Id
			v.CreatedAt = item.CreatedAt.Unix()
			v.UpdatedAt = item.UpdatedAt.Unix()
			messages = append(messages, v)
		}
	}
	resp.SUCCESS(c, messages)
}

// Remove godoc
// @Summary      删除会话
// @Description  删除会话
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Param        chat_id   query     string  true  "会话Id"
// @Success      200  {object}  types.BizVo{}
// @Router       /api/chat/remove [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) Remove(c *gin.Context) {
	chatId := h.GetTrim(c, "chat_id")
	// 判断参数是否为空
	if utils.IsEmptyValue(chatId) {
		resp.ERROR(c, types.InvalidArgs)
		return
	}

	// 获取登录的用户信息
	user, err := h.GetLoginUser(c)
	if err != nil {
		resp.NotAuth(c)
		return
	}
	// 删除会话
	res := h.DB.Where("user_id = ? and chat_id = ?", user.Id, chatId).Delete(&model.ChatItem{})
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+err.Error())
		return
	}

	// 删除当前会话的聊天记录
	res = h.DB.Where("user_id = ? and chat_id = ?", user.Id, chatId).Delete(&model.ChatMessage{})
	if res.Error != nil {
		resp.ERROR(c, "操作数据库出现错误："+err.Error())
		return
	}

	// TODO 是否要删除 MidJourney 会话记录和图片文件

	// 清空会话上下文
	h.ClearChatCtx(chatId)
	resp.SUCCESS(c, types.OkMsg)
}

// Detail godoc
// @Summary      对话详情，用户导出对话
// @Description  对话详情，用户导出对话
// @Tags         前台-用户会话
// @Accept       json
// @Produce      json
// @Param        chat_id   query     string  true  "会话Id"
// @Success      200  {object}  types.BizVo{data=vo.ChatItem}
// @Router       /api/chat/detail [get]
// @Security ApiKeyAuth
func (h *ChatOpenAiHandler) Detail(c *gin.Context) {
	chatId := h.GetTrim(c, "chat_id")
	// 判断参数是否为空
	if utils.IsEmptyValue(chatId) {
		resp.ERROR(c, types.InvalidArgs)
		return
	}

	var chatItem model.ChatItem
	// 查询会话
	res := h.DB.Where("chat_id = ?", chatId).First(&chatItem)
	if res.Error != nil {
		resp.ERROR(c, "No chat found")
		return
	}

	var role model.ChatRole
	// 查询角色信息
	res = h.DB.Where("id", chatItem.RoleId).First(&role)
	if res.Error != nil {
		resp.ERROR(c, "Role not found")
		return
	}

	// 查询会话使用的模型
	var chatModel model.ChatModel
	res = h.DB.Where("value = ?", chatItem.Model).First(&chatModel)
	if res.Error != nil {
		log.Errorf("没有找到会话对应的模型：%s\n", res.Error.Error())
	}

	var chatItemVo vo.ChatItem
	err := utils.CopyObject(chatItem, &chatItemVo)
	if err != nil {
		resp.ERROR(c, "拷贝数据时出现错误："+err.Error())
		return
	}
	chatItemVo.RoleName = role.Name
	chatItemVo.ModelId = chatModel.Id
	resp.SUCCESS(c, chatItemVo)
}
